package com.zhiwen.domain.consumer;

import com.rabbitmq.client.Channel;
import com.zhiwen.common.enums.NotificationType;
import com.zhiwen.config.RabbitMQConfig;
import com.zhiwen.domain.entity.Notification;
import com.zhiwen.domain.event.NotificationEvent;
import com.zhiwen.mapper.NotificationMapper;
import com.zhiwen.service.NotificationService;
import com.zhiwen.service.NotificationTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 通知消息消费者
 */
@Slf4j
@Component
public class NotificationConsumer {

    @Autowired
    private NotificationService notificationService;

    @Autowired
    private NotificationTemplateService templateService;

    @Autowired
    private NotificationMapper notificationMapper;

    /**
     * 处理问题相关通知队列中的消息
     */
    @RabbitListener(queues = RabbitMQConfig.QUESTION_NOTIFICATION_QUEUE)
    public void handleQuestionNotification(@Payload NotificationEvent event,
                                          Channel channel,
                                          @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到问题相关通知队列消息: {}", event);
        try {
            processNotification(event);
            // 手动确认消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理问题通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝消息失败", ex);
            }
        }
    }

    /**
     * 处理回答相关通知队列中的消息
     */
    @RabbitListener(queues = RabbitMQConfig.ANSWER_NOTIFICATION_QUEUE)
    public void handleAnswerNotification(@Payload NotificationEvent event,
                                        Channel channel,
                                        @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到回答相关通知队列消息: {}", event);
        try {
            processNotification(event);
            // 手动确认消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理回答通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝消息失败", ex);
            }
        }
    }

    /**
     * 处理评论相关通知队列中的消息
     */
    @RabbitListener(queues = RabbitMQConfig.COMMENT_NOTIFICATION_QUEUE)
    public void handleCommentNotification(@Payload NotificationEvent event,
                                         Channel channel,
                                         @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到评论相关通知队列消息: {}", event);
        try {
            processNotification(event);
            // 手动确认消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理评论通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝消息失败", ex);
            }
        }
    }

    /**
     * 处理系统通知队列中的消息
     */
    @RabbitListener(queues = RabbitMQConfig.SYSTEM_NOTIFICATION_QUEUE)
    public void handleSystemNotification(@Payload NotificationEvent event,
                                        Channel channel,
                                        @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到系统通知队列消息: {}", event);
        try {
            processNotification(event);
            // 手动确认消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理系统通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝消息失败", ex);
            }
        }
    }

    /**
     * 处理死信队列中的消息（处理失败的消息）
     */
    @RabbitListener(queues = "notification.dlq")
    public void handleDeadLetterQueue(@Payload Message message,
                                     Channel channel,
                                     @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.warn("接收到死信队列消息: {}", message);
        try {
            // 记录死信消息
            log.error("死信消息详情: {}", message);
            // 可以选择保存到数据库进行人工处理

            // 确认死信消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理死信消息失败", e);
            try {
                // 死信处理失败，拒绝消息但不重新入队
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝死信消息失败", ex);
            }
        }
    }

    /**
     * 处理点赞通知队列中的消息
     */
    @RabbitListener(queues = RabbitMQConfig.LIKE_NOTIFICATION_QUEUE)
    public void handleLikeNotification(@Payload NotificationEvent event,
                                      Channel channel,
                                      @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到点赞通知消息: {}", event);
        try {
            processNotification(event);
            // 手动确认消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理点赞通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝消息失败", ex);
            }
        }
    }

    /**
     * 处理关注通知队列中的消息
     */
    @RabbitListener(queues = RabbitMQConfig.FOLLOW_NOTIFICATION_QUEUE)
    public void handleFollowNotification(@Payload NotificationEvent event,
                                        Channel channel,
                                        @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到关注通知消息: {}", event);
        try {
            processNotification(event);
            // 手动确认消息
            channel.basicAck(tag, false);
        } catch (Exception e) {
            log.error("处理关注通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝消息失败", ex);
            }
        }
    }

    /**
     * 处理通知
     */
    private void processNotification(NotificationEvent event) {
        if (event == null) {
            log.warn("通知事件为空，无法处理");
            return;
        }

        try {
            // 避免循环调用，不要通过NotificationService再次发送消息
            // 直接使用NotificationMapper保存通知
            Map<String, Object> params = buildNotificationParams(event);

            NotificationType type = null;
            switch (event.getType()) {
                case 1: // 问题回答
                    type = NotificationType.QUESTION_ANSWERED;
                    break;
                case 2: // 回答评论
                    type = NotificationType.ANSWER_COMMENTED;
                    break;
                case 3: // 回答被采纳
                    type = NotificationType.ANSWER_ACCEPTED;
                    break;
                case 4: // 内容审核
                    type = NotificationType.CONTENT_REVIEWED;
                    break;
                case 5: // 系统通知
                    type = NotificationType.SYSTEM_NOTICE;
                    break;
                case 6: // 内容点赞
                    type = NotificationType.CONTENT_LIKED;
                    break;
                case 7: // 用户关注
                    type = NotificationType.USER_FOLLOWED;
                    break;
                default:
                    log.warn("未知通知类型: {}", event.getType());
                    return;
            }

            if (type != null) {
                processNotificationDirectly(event, type, params);
            }
        } catch (Exception e) {
            log.error("处理通知异常", e);
            throw e;
        }
    }

    /**
     * 直接处理通知，避免循环调用
     */
    private void processNotificationDirectly(NotificationEvent event, NotificationType type, Map<String, Object> params) {
        try {
            // 使用templateService获取标题和内容
            String title = templateService.getNotificationTitle(type, params);
            String content = templateService.getNotificationContent(type, params);

            // 创建通知实体
            Notification notification = new Notification();
            notification.setType(type.getValue());
            notification.setTitle(title);
            notification.setContent(content);
            notification.setReceiverId(event.getReceiverId());
            notification.setSenderId(event.getSenderId());
            notification.setIsRead(0);
            notification.setCreateTime(LocalDateTime.now());
            notification.setUpdateTime(LocalDateTime.now());
            notification.setDeleted(0);

            // 设置关联ID
            Long relatedId = null;
            if (event.getQuestionId() != null) {
                relatedId = event.getQuestionId();
            } else if (event.getAnswerId() != null) {
                relatedId = event.getAnswerId();
            } else if (event.getCommentId() != null) {
                relatedId = event.getCommentId();
            } else if (event.getContentId() != null) {
                relatedId = event.getContentId();
            }

            if (relatedId != null) {
                notification.setRelatedId(relatedId);
            }

            // 直接使用mapper保存通知
            notificationMapper.insert(notification);

            log.info("通知保存成功: {}", notification.getId());
        } catch (Exception e) {
            log.error("保存通知失败", e);
            throw e;
        }
    }

    /**
     * 构建通知参数
     */
    private Map<String, Object> buildNotificationParams(NotificationEvent event) {
        Map<String, Object> params = new HashMap<>();

        // 添加基本参数
        if (event.getQuestionId() != null) {
            params.put("questionId", event.getQuestionId());
        }
        if (event.getAnswerId() != null) {
            params.put("answerId", event.getAnswerId());
        }
        if (event.getCommentId() != null) {
            params.put("commentId", event.getCommentId());
        }
        if (event.getSenderId() != null) {
            params.put("senderId", event.getSenderId());
        }
        if (event.getReceiverId() != null) {
            params.put("receiverId", event.getReceiverId());
        }
        if (event.getContentType() != null) {
            params.put("contentType", event.getContentType());
        }
        if (event.getContentId() != null) {
            params.put("contentId", event.getContentId());
        }
        if (event.getReviewResult() != null) {
            params.put("reviewResult", event.getReviewResult());
        }
        if (event.getRemark() != null) {
            params.put("remark", event.getRemark());
        }
        if (event.getTitle() != null) {
            params.put("title", event.getTitle());
        }
        if (event.getContent() != null) {
            params.put("content", event.getContent());
        }

        return params;
    }

    /**
     * 批量处理通知消息
     */
    @RabbitListener(queues = "notification.batch.queue", concurrency = "3-5")
    public void handleBatchNotifications(@Payload List<NotificationEvent> events,
                                         Channel channel,
                                         @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
        log.info("接收到批量通知消息，共{}条", events.size());
        try {
            // 批量处理通知
            for (NotificationEvent event : events) {
                processNotification(event);
            }
            // 手动确认消息
            channel.basicAck(tag, false);
            log.info("批量通知处理完成，共{}条", events.size());
        } catch (Exception e) {
            log.error("批量处理通知消息失败", e);
            try {
                // 消息处理失败，拒绝消息但不重新入队，避免无限循环
                channel.basicNack(tag, false, false);
            } catch (IOException ex) {
                log.error("拒绝批量消息失败", ex);
            }
        }
    }
}
